﻿using System;
using System.Collections;
using System.IO;
using System.Reflection;
using java = biz.ritter.javapi;
using biz.ritter.javapi.io;


namespace biz.ritter.javapi.lang
{
    /// <summary>
    /// Summary description for FunctionList.
    /// </summary>
    public class FunctionList : MarshalByRefObject, IEnumerable
    {
        public class FunctionListEnumerator : IEnumerator
        {
            int currentItem = -1;
            FunctionList functionList;
            public FunctionListEnumerator(FunctionList functionList)
            {
                this.functionList = functionList;
            }

            public void Reset()
            {
                currentItem = -1;
            }

            public bool MoveNext()
            {
                currentItem++;
                if (currentItem == functionList.functions.Count)
                    return false;
                else
                    return true;
            }

            public object Current
            {
                get
                {
                    return functionList.functions[currentItem];
                }
            }
        }

        ArrayList functions = new ArrayList();

        public FunctionList()
        {
            //
            // TODO: Add constructor logic here
            //
        }

        internal ArrayList Functions
        {
            get
            {
                return functions;
            }
        }

        public IEnumerator GetEnumerator()
        {
            return new FunctionListEnumerator(this);
        }

        public void Add(Function function)
        {
            functions.Add(function);
        }

        /// <summary>
        /// Merge a function list into the current one
        /// </summary>
        /// <param name="functionList"></param>
        public void Merge(FunctionList functionList)
        {
            foreach (Function function in functionList.Functions)
            {
                functions.Add(function);
            }
        }

        // walk through all the functions in a type,
        // and add them to the list...
        public void AddAllFromType(Type type)
        {
            // TODO: Figure out how to deal with 
            // instance methods here. It would require creating
            // an instance here...

            MethodInfo[] methods = type.GetMethods(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public);
            object instance = null;

            // any function that takes parameters
            // of type double and returns double
            // is fine with us...
            foreach (MethodInfo m in methods)
            {
                // if it doesn't return double, skip it
                if (m.ReturnType != typeof(double))
                    continue;

                ArrayList paramNames = new ArrayList();
                bool allDouble = true;
                foreach (ParameterInfo p in m.GetParameters())
                {
                    if (p.ParameterType != typeof(double))
                        allDouble = false;

                    paramNames.Add(p.Name);
                }
                if (!allDouble)
                    continue;

                string funcName =
                    type.Name + "." +
                    m.Name + "(" +
                    String.Join(",", (string[])paramNames.ToArray(typeof(string))) + ")";

                // if it's an instance method, we'll
                // need to create an instance to use
                // when creating the delegate...
                if (!m.IsStatic)
                {
                    if (instance == null)
                    {
                        try
                        {
                            instance = Activator.CreateInstance(type);
                        }
                        catch (MissingMethodException)
                        {
                            continue;
                        }
                    }
                }

                functions.Add(new Function(funcName, m, instance));
            }
        }
    }
}
